<!DOCTYPE html> 
<html>
<head>
<title>Skyline75489</title>
<meta charset='utf-8'>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<link rel="stylesheet" href="../static/styles/github.css">
<link rel="stylesheet" href="../static/post.css">
</head>
<body>

<div class="wrapper">
<div class="header">
	<span class="blog-name">Skyline75489</span>

<a class="nav" href="../index.html">Home</a>
<a class="nav" href="about.html">About</a>
</div>
<div class="content">

<h1>Python 3.5 Coroutine 特性初探</h1>
<p>Python 3.5 终于在前两天（13号）放出了正式版，其中最受大家关注的特性大概就是全新加入的 Coroutine 支持了。</p>
<p>在 Python 3.5 之前，我们可以使用 Python 的 generator 变相地写出 coroutine 的效果，在 Python 3.3 中还加入了 <code>yield from</code> 关键字，增强了对于 coroutine 的支持。现在在 Python 3.5 中，终于加入了原生的 coroutine 支持。本文会使用几个小例子，介绍一下 Python 3.5 中 coroutine 的使用。</p>
<p>Python 3.5 中为 coroutine 加入了两个新的关键字，<code>async</code> 和 <code>await</code>， <code>async</code> 用于定义 coroutine，<code>await</code> 用于从 coroutine 返回。</p>
<p>首先定义一个 coroutine:</p>
<pre><code class="lang-python">async def a():
    print(&#39;a1&#39;)
    print(&#39;a2&#39;)
    print(&#39;a3&#39;)
</code></pre>
<p>这个 coroutine 看起来像是函数，但是实际上它属于一个单独的 coroutine 类型，并且不能直接调用，如果我们直接调用它：</p>
<pre><code class="lang-python">a()
</code></pre>
<p>会报错：</p>
<pre><code>RuntimeWarning: coroutine 'a' was never awaited
  a()
</code></pre>
<p>可以打印一下它的类型：</p>
<pre><code class="lang-python">print(a())
</code></pre>
<p>会打印出类似下面的输出：</p>
<pre><code>&lt;coroutine object a at 0x10190e7d8&gt;
</code></pre>
<p>想要调用它，需要使用 send 函数：</p>
<pre><code class="lang-python">co = a()
try:
    co.send(None)
except StopIteration:
    pass
</code></pre>
<p>可以看到，coroutine 的使用和 generator 其实是非常接近的，在底层 coroutine 也确实是基于 generator 实现的。 Python 3.5 还专门提供了一个 decorator <code>types.coroutine()</code> 用于把旧式的 yield from 写法的 coroutine 转换成原生的 coroutine 类型。</p>
<pre><code class="lang-python">
import types

@types.coroutine
def a():
    print(&#39;a1&#39;)
    yield
</code></pre>
<p>同样使用上面的 <code>send</code> 方法进行调用，这段代码和原生 coroutine 运行的效果是一样的。</p>
<p>在一个 coroutine 中，可以使用 <code>await</code> 用于从别的 couroutine 返回：</p>
<pre><code class="lang-python">async def a():
    print(&#39;a1&#39;)
    print(&#39;a2&#39;)
    await b()
    print(&#39;a3&#39;)

async def b():
    print(&#39;b1&#39;)
    print(&#39;b2&#39;)
    print(&#39;b3&#39;)
</code></pre>
<p>这段代码中，<code>await</code> 会导致 b() 执行，等 b() 执行完毕之后，再回来执行 a()。</p>
<p>需要注意的是， <code>await</code> 只能在 <code>async def</code> 中使用，同时 <code>await</code> 后面跟的类型必须为 <code>awaitable</code>，具体可以有下面几种：</p>
<ul>
<li>原生的 coroutine，使用 <code>async def</code> 定义</li>
<li>使用 <code>types.coroutine</code> 包装过的基于 generator 的方法（如上面的例子中的方法）</li>
<li>实现了 <code>__await__</code> 的对象</li>
<li>使用 CPython API 实现了 <code>tp_as_async.am_await</code> 的对象（和上一条类似）</li>
</ul>
<p>更多有关 coroutine 的信息，可以参考 <a href="https://www.python.org/dev/peps/pep-0492/">PEP-0492</a>。</p>


</div>
</div>
<script src="../static/highlight.pack.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
</body>

</html>
